use std::rc::Rc;
use std::cell::RefCell;
use std::rc::Weak;
use std::cell::Cell;
use std::collections::HashMap;

//Cell
// Cell 有如下特点：
//
// Cell<T> 只能用于 T 实现了 Copy 的情况；
// .get()
// .get() 方法，返回内部值的一个拷贝。比如：

#[test]
pub fn cell_demo(){
    let c = Cell::new(5);

    let five = c.get();

    c.set(10);
    println!("{},{}", five, c.get()); //5, 10
}


///RefCell<T>用来实现内部可变性，internal mutability，即数据可以在自身的方法中改变自身，但对外是不可变的。
///Box<T>, Rc<T>, RefCell<T>比较：
//
// Rc<T>，允许多重拥有，不可变借用，编译时检查
//
// Box<T>，单一拥有者，可变或不可变借用，编译时检查(Deref, DerefMut)

//RefCell<T>, 单一拥有者，可变或不可变借用，运行时检查。可变不可变是对外的，都可以在内部改变。其实是把不安全的操作包装在安全的接口中，
// 适用于：我比编译器明白，我知道我在干什么。


#[test]
pub fn refCell_demo(){
    let shared_map: Rc<RefCell<_>> = Rc::new(RefCell::new(HashMap::new()));
    shared_map.borrow_mut().insert("africa", 92388);
    shared_map.borrow_mut().insert("kyoto", 11837);
    shared_map.borrow_mut().insert("piccadilly", 11826);
    shared_map.borrow_mut().insert("marbles", 38);
}

//消息发送者
#[derive(Debug)]
struct MockMessenger {
    //要发生的消息
    sent_messages: Vec<String>,
    sent_refcell_messages: RefCell<Vec<String>>,
    count: RefCell<i32>,
}

impl MockMessenger {
    fn new() -> MockMessenger  {
            MockMessenger {sent_messages: vec![],
            sent_refcell_messages: RefCell::new(vec![]),
            count: RefCell::new(0)
        }
    }
    //self是不可变引用
    fn send(&self, message: &str) {
        //编译出错 self是不可变引用，不能修改内部属性的值
        //self.sent_messages.push(String::from(message));
        //RefCell数据可以在自身的方法中改变自身
        self.sent_refcell_messages.borrow_mut().push(String::from(message));
        *(self.count.borrow_mut()) += 34;
    }
}


pub fn  refCell_demo1(){
    let m = MockMessenger::new();
    m.send("this is a msg");
    println!("{:?}", m); //MockMessenger { sent_messages: [], sent_refcell_messages: RefCell { value: ["this is a msg"] } }

}

#[derive(Debug)]
enum List{
    Cons(Rc<RefCell<i32>>, Rc<List>),
    Nil,
}
/// Rc 嵌套 RefCell 多重拥有兼可变
pub fn refCell_demo2(){
    let value = Rc::new(RefCell::new(5));
    //Rc::clone 引用计数加1，不会执行数据的深度拷贝操作
    let a = Rc::new(List::Cons(Rc::clone(&value), Rc::new(List::Nil)));
    let b = List::Cons(Rc::new(RefCell::new(6)), Rc::clone(&a));
    let c = List::Cons(Rc::new(RefCell::new(10)), Rc::clone(&a));

    *(value.borrow_mut()) += 10; //可以修改值
    println!("a after = {:?}", a);
    println!("b after = {:?}", b);
    println!("c after = {:?}", c);

}

//不可变借用被包裹值。同时可存在多个不可变借用。
#[test]
pub fn refCell_demo3(){
    let c = RefCell::new(5);

    let borrowed_five = c.borrow();
    let borrowed_five2 = c.borrow();

    println!("{},{}", borrowed_five, borrowed_five2); // 5, 5
}

//  不能同时存在不可变借用和可变借用
#[test]
pub fn refCell_demo4(){
    let c = RefCell::new(5);

     //let borrowed_five = c.borrow();

     let mut b = c.borrow_mut();

}
//取出包裹值
#[test]
pub fn refCell_demo5(){
    let c = RefCell::new(5);

    let five = c.into_inner();
    println!("{}", five);
}


//下面这个示例，表述的是如何实现两个对象的循环引用。综合演示了 Rc, Weak, RefCell 的用法
struct Owner {
    name: String,
    gadgets: RefCell<Vec<Weak<Gadget>>>, //Weak 是一个指针，但不增加引用计数
    // 其他字段
}
struct Gadget {
    id: i32,
    owner: Rc<Owner>,
    // 其他字段
}

#[test]
pub fn cycle_ref_demo(){
    // 创建一个可计数的Owner。
    // 注意我们将gadgets赋给了Owner。
    // 也就是在这个结构体里， gadget_owner包含gadets
    let gadget_owner : Rc<Owner> = Rc::new(
        Owner {
            name: "Gadget Man".to_string(),
            gadgets: RefCell::new(Vec::new()),
        }
    );
    // 首先，我们创建两个gadget，他们分别持有 gadget_owner 的一个引用。
    let gadget1 = Rc::new(Gadget{id: 1, owner: gadget_owner.clone()});
    let gadget2 = Rc::new(Gadget{id: 2, owner: gadget_owner.clone()});

    // 我们将从gadget_owner的gadgets字段中持有其可变引用
    // 然后将两个gadget的Weak引用传给owner。
    gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget1));
    gadget_owner.gadgets.borrow_mut().push(Rc::downgrade(&gadget2));

    // 遍历 gadget_owner的gadgets字段
    for gadget_opt in gadget_owner.gadgets.borrow().iter() {

        // gadget_opt 是一个 Weak<Gadget> 。 因为 weak 指针不能保证他所引用的对象
        // 仍然存在。所以我们需要显式的调用 upgrade() 来通过其返回值(Option<_>)来判
        // 断其所指向的对象是否存在。
        // 当然，这个Option为None的时候这个引用原对象就不存在了。
        let gadget = gadget_opt.upgrade().unwrap();
        println!("Gadget {} owned by {}", gadget.id, gadget.owner.name);
    }
}
//gadget_owner, gadget1和daget2都被销毁。
// 具体是，因为这几个结构体之间没有了强引用（`Rc<T>`），所以，当他们销毁的时候。
// 首先 gadget1和gadget2被销毁。
// 然后因为gadget_owner的引用数量为0，所以这个对象可以被销毁了。
// 循环引用问题也就避免了